﻿/*
Copyright (C) 2009 Matthew Perry

This library is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This libary/program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
using System;
using BaseTools.Helpers;
using BaseTools.XS;
using BaseTools.Configuration;
using BaseTools.Configuration.Parsers;
using System.IO;
using BaseTools.Searching;

namespace XConfTool
{
	class Program
	{
		public static TextWriter cerr = Console.Error;
		
		
		public static void NEA()
		{
			cerr.WriteLine("XCONFTOOL: Not enough arguments");
		}
		public static void Protocolify(string text, ref IConfig ic, ref string path)
		{
			if (text.Contains("://"))
					{
						string[] prot = text.Split(new string[] {"://"}, 2, StringSplitOptions.None);
						switch(prot[0])
						{
							case "source":
								ic = new SourceConfig();
								break;
							case "ini":
								ic = new IniIConfig();
								break;
							default:
							case "general":
								ic = new GeneralConfig();
								break;
						}
						path = prot[1];
					}
		}
		public static void Main(string[] args)
		{
			try
			{
				XConf.EnsureXConf();
				if (args.Length < 2)
				{
					cerr.WriteLine(
						"Command-line tool for managing XConf\n\n" +
						"XCONFTOOL [/R | /r] [/E | /e] [/W | /w] filename [newdata | newfilename] keys...\n\n" +
						"/R         Read the data into standard output\n" +
						"/r         Same as /R but case sensitive\n" +
						"/E         Print \"true\" or \"false\" depending whether the key exists\n" +
						"/e         Same as /E but case sensitive\n" +
						"/W         Write the string into the file\n" +
						"/w         Same as /W but case sensitive\n" +
						"/C         Write the config into the file\n" +
						"/c         Same as /C but case sensitive\n" +
						"\n" +
						"\n" +
						"filename   The filename relative to XConf\n" +
						"           default format is .xbt. Protocols\n" +
						"           for the config handler are available\n" +
						"           source:// general:// ini:// (ini is very inefficient)\n" +
						"           If the filename starts with @ it is absolute\n" +
						"           If it starts with * it is relative to XSettings\n" +
						"keys       The keynames in the file, each one\n" +
						"           goes deeper into the structure"
					);
				}
				else
				{
					
					IConfig ic = new GeneralConfig();
					/*if (args[1].Contains("://"))
					{
						string[] prot = args[1].Split(new string[] {"://"}, 2, StringSplitOptions.None);
						switch(prot[0])
						{
							case "source":
								ic = new SourceConfig();
								break;
							case "ini":
								ic = new IniIConfig();
								break;
							default:
							case "general":
								ic = new GeneralConfig();
								break;
						}
						args[1] = prot[1];
					}*/
					Protocolify(args[1], ref ic, ref args[1]);
					
					string filename = args[1];
					
					if (filename.StartsWith("@"))
					{
						filename = IOHelper.CleanPath(filename.Substring(1));
					}
					else if (filename.StartsWith("*"))
					{
						filename = IOHelper.RelativeTo(XSettings.SettingsFolder, filename.Substring(1));
					}
					else
					{
						filename = XConf.RelativeTo(filename);
					}
					
					string[] a1s = filename.Split('\\', '/');
					
					
					if (!a1s[a1s.Length-1].Contains("."))
					{
						filename += ".xbt";
					}
					
					switch(args[0])
					{
						case "/R":
						case "/r":
							
							if (args.Length < 3)
							{
								NEA();
							}
							else
							{
								ConfigList lst = ic.LoadConfiguration(filename);
								if (lst == null)
								{
									cerr.WriteLine("XCONFTOOL: Could not open file \"" + filename + "\"");
								}
								else
								{
									bool casesens = (args[0] == "/r");
									string name = "";
									for(int i=2;i<args.Length;i++)
									{
										if (name.Length > 0)
											name += "/";
										
										string s = args[i];
										name += s;
										
										if (i == (args.Length-1))
										{
											ConfigPair p = lst.FindPair(new StringValidator(s, casesens));
											if (p != null)
											{
												if (!p.DataIsList)
												{
													Console.WriteLine(p.Data.ToString());
												}
												else
												{
													if ((ic is IniIConfig))
													{
														ConfigList l = new ConfigList();
														l.AddPair(p);
														
														Console.WriteLine(ic.WriteConfiguration(l));
													}
													else
													{
														Console.WriteLine(ic.WriteConfiguration(p.DataAsList));
													}
												}
											}
											else
											{
												cerr.WriteLine("XCONFTOOL: Could not locate " + name + " within the configuration");
												break;
											}
										}
										else
										{
											if (lst.HasSection(new StringValidator(s, casesens)))
											{
												lst = lst.GetSection(new StringValidator(s, casesens));
											}
											else
											{
												cerr.WriteLine("XCONFTOOL: Could not locate " + name + " within the configuration");
												break;
											}
										}
									}
								}
							}
							
							break;
						case "/E":
						case "/e":
							
							if (args.Length < 3)
							{
								NEA();
							}
							else
							{
								ConfigList lst = ic.LoadConfiguration(filename);
								if (lst == null)
								{
									cerr.WriteLine("XCONFTOOL: Could not open file \"" + args[1] + "\"");
									Console.WriteLine("false");
								}
								else
								{
									bool casesens = (args[0] == "/e");
									string name = "";
									for(int i=2;i<args.Length;i++)
									{
										if (name.Length > 0)
											name += "/";
										
										string s = args[i];
										name += s;
										
										if (i == (args.Length-1))
										{
											ConfigPair p = lst.FindPair(new StringValidator(s, casesens));
											if (p != null)
											{
												Console.WriteLine("true");
											}
											else
											{
												Console.WriteLine("false");
												break;
											}
										}
										else
										{
											if (lst.HasSection(new StringValidator(s, casesens)))
											{
												lst = lst.GetSection(new StringValidator(s, casesens));
											}
											else
											{
												Console.WriteLine("false");
												break;
											}
										}
									}
								}
							}
							
							break;
						case "/W":
						case "/w":
							
							if (args.Length < 4)
							{
								NEA();
							}
							else
							{
								ConfigList lst = ic.LoadConfiguration(filename), olst = lst;
								if (lst == null)
								{
									cerr.WriteLine("XCONFTOOL: Could not open file \"" + args[1] + "\"");
								}
								else
								{
									bool casesens = (args[0] == "/e");
									string name = "";
									for(int i=3;i<args.Length;i++)
									{
										if (name.Length > 0)
											name += "/";
										
										string s = args[i];
										name += s;
										
										if (i == (args.Length-1))
										{
											ConfigPair p = lst.FindPair(new NoListValidator(s, casesens));
											if (p != null)
											{
												p.Data = args[2];
											}
											else
											{
												lst.AddString(s, args[2]);
											}
										}
										else
										{
											if (lst.HasSection(new StringValidator(s, casesens)))
											{
												lst = lst.GetSection(new StringValidator(s, casesens));
											}
											else
											{
												ConfigList li = new ConfigList();
												lst.AddSection(s, li);
												lst = li;
											}
										}
									}
									
									ic.SaveConfiguration(filename, olst);
								}
							}
							
							break;
							
						case "/C":
						case "/c":
							
							if (args.Length < 4 && !(ic is IniIConfig))
							{
								NEA();
							}
							else
							{
								ConfigList lst = ic.LoadConfiguration(filename), olst = lst;
								if (lst == null)
								{
									cerr.WriteLine("XCONFTOOL: Could not open file \"" + args[1] + "\"");
								}
								else
								{
									bool casesens = (args[0] == "/c");
									string name = "";
									
									if (ic is IniIConfig)
									{
										lst = ic.LoadConfiguration(IOHelper.CleanPath(args[2]));
										foreach(ConfigPair p in lst)
										{
											ConfigPair q = olst.GetPair(new StringValidator(p.Key, casesens));
											
											if (q == null)
												olst.AddPair(p);
											else
											{
												q.Key = p.Key;
												q.Data = p.Data;
											}
										}
									}
									else
									{
										for(int i=3;i<args.Length;i++)
										{
											if (name.Length > 0)
												name += "/";
											
											string s = args[i];
											name += s;
											
											if (i == (args.Length-1))
											{
												args[2] = IOHelper.CleanPath(args[2]);
												ConfigPair p = lst.FindPair(new InListValidator(s, casesens));
												if (p != null)
												{
													p.Data = ic.LoadConfiguration(args[2]);
												}
												else
												{
													lst.AddPair(new ConfigPair(s, ic.LoadConfiguration(args[2])));
												}
											}
											else
											{
												if (lst.HasSection(new StringValidator(s, casesens)))
												{
													lst = lst.GetSection(new StringValidator(s, casesens));
												}
												else
												{
													ConfigList li = new ConfigList();
													lst.AddSection(s, li);
													lst = li;
												}
											}
										}
									}
								}
								ic.SaveConfiguration(filename, olst);
							}
							
							break;
						case "/T":
							
							break;
					}
				}
			}
			catch(Exception ex)
			{
				cerr.WriteLine("XCONFTOOL: " + ex.Message);
			}
		}
	}
}